<?php

namespace console\controllers;

use Yii;
use common\components\wechat\pay\Pay;
use common\models\ClearOrderSon;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use yii\console\Controller;

class TestController extends Controller{
    /**
     * 统一下单接口
     * @param string $out_trade_no 商户订单号
     * @param string $total_fee 订单总金额（单位：分）
     * @param string $body 商品描述
     * @param string $spbill_create_ip 终端IP
     * @param string $trade_type 交易类型（native）
     * @param string $product_id 商品ID（trade_type=NATIVE时必填）
     * @return array
     */
    public function unifiedOrder($out_trade_no, $total_fee, $body, $spbill_create_ip, $product_id)
    {
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

        $params = [
            'appid' => Yii::$app->params['payment']['appId'],
            'mch_id' => Yii::$app->params['payment']['mchId'],
            'nonce_str' => $this->createNonceStr(),
            'body' => $body,
            'out_trade_no' => $out_trade_no,
            'total_fee' => $total_fee,
            'spbill_create_ip' => $spbill_create_ip,
            'notify_url' => Yii::$app->params['payment']['notifyUrl'],
            'trade_type' => 'NATIVE',
            'product_id' => $product_id,
        ];

        // 生成签名
        $params['sign'] = $this->makeSign($params);

        // 转换XML格式
        $xml = $this->arrayToXml($params);

        // 发送请求
        $response = $this->postXmlCurl($xml, $url);

        // 解析返回结果
        $result = $this->xmlToArray($response);

        return $result;
    }

    /**
     * 生成随机字符串
     * @param int $length
     * @return string
     */
    private function createNonceStr($length = 32)
    {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str = '';
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * 生成签名
     * @param array $params
     * @return string
     */
    private function makeSign($params)
    {
        // 过滤空值
        $params = array_filter($params);

        // 按字典序排序参数
        ksort($params);

        // 生成URL键值对格式
        $string = '';
        foreach ($params as $k => $v) {
            $string .= $k . '=' . $v . '&';
        }

        // 拼接API密钥
        $string .= 'key=' . Yii::$app->params['payment']['apiKey'];

        // MD5加密并转为大写
        return strtoupper(md5($string));
    }

    /**
     * 数组转XML
     * @param array $arr
     * @return string
     */
    private function arrayToXml($arr)
    {
        $xml = '<xml>';
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= '<' . $key . '>' . $val . '</' . $key . '>';
            } else {
                $xml .= '<' . $key . '><![CDATA[' . $val . ']]></' . $key . '>';
            }
        }
        $xml .= '</xml>';
        return $xml;
    }

    /**
     * XML转数组
     * @param string $xml
     * @return array
     */
    private function xmlToArray($xml)
    {
        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $arr;
    }

    /**
     * 以post方式提交xml到对应的接口url
     * @param string $xml 需要post的xml数据
     * @param string $url url
     * @param bool $useCert 是否需要证书，默认不需要
     * @param int $second url执行超时时间，默认30s
     * @return mixed
     */
    private function postXmlCurl($xml, $url, $useCert = false, $second = 30)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);

        // 设置证书
        if ($useCert == true) {
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLCERT, Yii::$app->params['payment']['sslcert_path']);
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLKEY, Yii::$app->params['payment']['sslkey_path']);
        }

        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);

        $data = curl_exec($ch);

        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            throw new \Exception("curl出错，错误码:$error");
        }
    }

    public function actionNative(){
        /*$pay = new Pay();
        $pay->native('1', '123', '100');
        $result = $pay->wechat_native_order(
            '测试商品描述',
            'ORDER' . time(),
            100,  // 单位为分，100 表示 1元
        );
        var_dump($result);*/

        try {

            // 商户订单号
            $out_trade_no = date('YmdHis') . mt_rand(1000, 9999);
            // 订单金额（单位：分）
            $total_fee = 1; // 1分钱测试
            // 商品描述
            $body = '测试商品';
            // 客户端IP
            $spbill_create_ip = '121.43.48.92';
            // 商品ID
            $product_id = '123456789';

            $result = $this->unifiedOrder($out_trade_no, $total_fee, $body, $spbill_create_ip, $product_id);

            var_dump($result);
            if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
                // 获取支付二维码链接
                $code_url = $result['code_url'];

                // 生成二维码（可以使用第三方库如endroid/qr-code）
                // 这里简单输出二维码链接
                echo '请使用微信扫描以下二维码支付：<br>';
                echo '<img src="https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=' . urlencode($code_url) . '">';
                echo '<br>二维码链接：' . htmlspecialchars($code_url);
            } else {
                echo '下单失败：' . ($result['return_msg'] ?? $result['err_code_des'] ?? '未知错误');
            }
        } catch (\Exception $e) {
            echo '发生错误：' . $e->getMessage();
        }
    }

    public function actionDemo(){
        $mchid        = Yii::$app->params['payment']['mchId'];
        $appId        = Yii::$app->params['payment']['appId'];
        $serialNo     = Yii::$app->params['payment']['serialNo'];
        $apiV3Key     = Yii::$app->params['payment']['pubKey'];
        $notifyUrl    = Yii::$app->params['payment']['notifyUrl'];
        $privateKey   = Rsa::from('file://'.Yii::$app->params['payment']['keyPath'], Rsa::KEY_TYPE_PRIVATE);
        $platformCert = Rsa::from('file://'.Yii::$app->params['payment']['certPath'], Rsa::KEY_TYPE_PUBLIC);

        $client = Builder::factory([
            'mchid'      => $mchid,
            'serial'     => $serialNo,
            'privateKey' => $privateKey,
            'certs'      => [$serialNo => $platformCert],
        ]);

        $outTradeNo = 'wx_' . date('YmdHis') . rand(1000, 9999);

        $response = $client->post('/v3/pay/transactions/native', [
            'json' => [
                'mchid'        => $mchid,
                'appid'        => $appId,
                'description'  => '测试商品',
                'out_trade_no' => $outTradeNo,
                'notify_url'   => $notifyUrl,
                'amount' => [
                    'total' => 1,
                    'currency' => 'CNY',
                ],
            ]
        ]);

        $data = json_decode($response->getBody()->getContents(), true);
        var_dump($data);
    }

    public function actionIndex(){
        $total_fee = 1; // 单位：分
        $nonce_str = $this->createNonceStr();
        $out_trade_no = date('YmdHis') . mt_rand(1000, 9999);
        $params = [
            'appid' => Yii::$app->params['payment']['appId'],
            'mch_id' => Yii::$app->params['payment']['mchId'],
            'nonce_str' => $nonce_str,
            'body' => '测试商品',
            'out_trade_no' => $out_trade_no,
            'total_fee' => $total_fee,
            'spbill_create_ip' =>'121.43.48.92',
            'notify_url' => Yii::$app->params['payment']['notifyUrl'],
            'trade_type' => 'JSAPI',
            'openid' => 'oQvoG7MsD_2Ljuy5WYkKImnB6J0I'
        ];

        $params['sign'] = $this->makeSign($params);
        $xmlData = $this->arrayToXml($params);

        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $response = $this->postXmlCurl($xmlData, $url);

        $result = $this->xmlToArray($response);

        if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            $prepay_id = $result['prepay_id'];

            // 返回 JSAPI 调起支付参数
            $jsapiParams = [
                'appId' => Yii::$app->params['payment']['appId'],
                'timeStamp' => strval(time()),
                'nonceStr' => $this->createNonceStr(),
                'package' => "prepay_id=$prepay_id",
                'signType' => 'MD5',
            ];
            $jsapiParams['paySign'] = $this->makeSign($jsapiParams);
            var_dump($jsapiParams);
        } else {
            var_dump($result);
        }
    }

    public function genSign($nonceStr, $timeStamp, $url, $data){
        $key     = openssl_get_privatekey(file_get_contents(Yii::$app->params['payment']['certPath']));//这里是打开商户私钥证书
        $method  = 'POST'; //请求的方式
        $serialNo = Yii::$app->params['payment']['serialNo'];
        $mchid    = Yii::$app->params['payment']['mchId'];
        $message = $method . "\n" .$url. "\n" .$timeStamp . "\n" . $nonceStr . "\n" . $data . "\n"; //组合成一字符串 \n 需要每行携带，官方要求的
        openssl_sign($message, $rawSign, $key,'sha256WithRSAEncryption'); //sha256WithRSA 加密
        openssl_sign($message, $rawSign, $key,'sha256WithRSAEncryption'); //sha256WithRSA 加密
        $sign    = base64_encode($rawSign); //收到上面加密值做base64
        return  "WECHATPAY2-SHA256-RSA2048 mchid={$mchid},nonce_str=$nonceStr,timestamp=$timeStamp,serial_no=$serialNo,signature=$sign";
        //return base64_encode($rawSign);
    }
    public function curlPost($url, $data,$headers)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $response = curl_exec($ch);
        curl_close($ch);
        return json_decode($response, true);
    }
}